//------------------------------------------------------------------------------
// Fichiers d'ent�te utilis�s
//------------------------------------------------------------------------------
#include "SegmentModelizerOperator.hpp"
#include "Tools/Logger.hpp"
#include <math.h>

#define EPSILON_DISTANCE 5.0f

//------------------------------------------------------------------------------
// Définition de constantes
//------------------------------------------------------------------------------

namespace ImageAnalysis
{
	//----------------------------------------------------------------------
	// Constructeur
	//----------------------------------------------------------------------
	SegmentModelizerOperator::SegmentModelizerOperator( OutlineContainer* _outlineList, TSegmentContainerList* _outlinesSegmentsList):
	outlineList(_outlineList),
	outlinesSegmentsList(_outlinesSegmentsList), 
	width(_outlineList->GetWidth()), 
	height(_outlineList->GetHeight())
	{

	}

	//----------------------------------------------------------------------
	// Destructeur
	//----------------------------------------------------------------------
	SegmentModelizerOperator::~SegmentModelizerOperator( )
	{

	}

	//----------------------------------------------------------------------
	//
	//----------------------------------------------------------------------
	void SegmentModelizerOperator::Process( )
	{
		for(OutlineContainer::TOutlineContainerIterator itOutline = outlineList->GetStartOutline( ); itOutline !=outlineList->GetEndOutline( ); ++itOutline )
		{
			if((*itOutline)->GetNumberOfIndex()>1)
			{
				SegmentContainer * segments = new SegmentContainer( width, height );
				findSegments((*itOutline)->GetStartIndex(),(--(*itOutline)->GetEndIndex()), segments);
				outlinesSegmentsList->push_back(segments);
			}
		}
		
	}


	void SegmentModelizerOperator::findSegments(Outline::TOutlineIterator itBegin, Outline::TOutlineIterator itEnd, SegmentContainer * segments)
	{
		Outline::TOutlineIterator itDeb = itBegin;
		if(itDeb == itEnd)
		{
			SegmentContainer::Coordinates *  beginPoint = getCoordinates(itBegin);
			SegmentContainer::Coordinates *  endPoint = getCoordinates(itEnd);
			segments->AddSegment(new SegmentContainer::Segment(beginPoint,endPoint));
			return;
		}

		
		
		float distance = 0;
		Outline::TOutlineIterator itBiggest;
		for(Outline::TOutlineIterator itPixel = itDeb ; itPixel != itEnd; ++itPixel)
		{
			float d = ComputeDistance(itBegin,itPixel,itEnd);
			if(d>distance)
			{
				distance = d;
				itBiggest = itPixel;
			}
		}

		

		if (distance > EPSILON_DISTANCE)
		{
			findSegments(itBegin, itBiggest, segments);
			findSegments(itBiggest, itEnd, segments);
		}
		else
		{
			SegmentContainer::Coordinates *  beginPoint = getCoordinates(itBegin);
			SegmentContainer::Coordinates *  endPoint = getCoordinates(itEnd);
			segments->AddSegment(new SegmentContainer::Segment(beginPoint,endPoint));
			return;
		}
	}

	SegmentContainer::Coordinates * SegmentModelizerOperator::getCoordinates (Outline::TOutlineIterator it)
	{
		//Tools::ILogger::Log() <<*it<<"\n";
		SegmentContainer::Coordinates * point = new SegmentContainer::Coordinates( (*it)%width, (*it)/width );
		//Tools::ILogger::Log() << "x:" << point->x << "y:" << point->y << "\n";
		return point;
	}

	float SegmentModelizerOperator::ComputeDistance (Outline::TOutlineIterator itBegin,Outline::TOutlineIterator itMiddle,Outline::TOutlineIterator itEnd)
	{
		SegmentContainer::Coordinates *  beginPoint 	= getCoordinates(itBegin);
		SegmentContainer::Coordinates *  endPoint 	= getCoordinates(itEnd);
		SegmentContainer::Coordinates *  middlePoint 	= getCoordinates(itMiddle);

		//Calcul des distances des différents cotés du triangle
		float a = sqrt((endPoint->x-beginPoint->x)*(endPoint->x-beginPoint->x)+(endPoint->y-beginPoint->y)*(endPoint->y-beginPoint->y));
		float b = sqrt((endPoint->x-middlePoint->x)*(endPoint->x-middlePoint->x)+(endPoint->y-middlePoint->y)*(endPoint->y-middlePoint->y));
		float c = sqrt((middlePoint->x-beginPoint->x)*(middlePoint->x-beginPoint->x)+(middlePoint->y-beginPoint->y)*(middlePoint->y-beginPoint->y));

		//Calcul de la hauteur issu du point middle
		return (sqrt((4*b*b*c*c-((a*a-b*b-c*c)*(a*a-b*b-c*c)))/(2*a)));
	}

	
}

